/**
 * @file
 * @author Daniel White
 * @version 0.1
 * @brief FASTER THAN GMP, ALMOST
 * @section Description
 *
 * (I'll get round to this) asd
 */

/*
	TODO:
		* Check for non-decimal digits in SetFromString function
		* Speed up add and sub (they are used everywhere...)
		* Speed up div function (actually divide, rather than just subtracting)
		* Check for negatives when dividing
		* In many of the functions, check for NULL from malloc or realloc (add, sub, setfrom etc).
*/

#ifndef BIGINT_HEADER
#define BIGINT_HEADER

#include <stdbool.h>
#include <stdint.h>

typedef uint8_t BigInt_Digit;

typedef struct
{
	bool IsNegative;
	uint32_t Length;
	uint32_t Size;
	BigInt_Digit *Digits;
}BigInt;

void BigInt_NthRoot(BigInt *Result, BigInt Number, BigInt Root);				//TODO
void BigInt_Random(BigInt *Result, BigInt Min, BigInt Max);						//TODO

BigInt BigInt_Create();
void BigInt_Destroy(BigInt BigInt);
void BigInt_SetFromInt(BigInt *BigInt, int Value);
void BigInt_SetFromLong(BigInt *BigInt, long Value);
void BigInt_SetFromBigInt(BigInt *Output, BigInt Value);
void BigInt_Inc(BigInt *Number);
void BigInt_Dec(BigInt *Number);
void BigInt_Negate(BigInt *Number);
void BigInt_Add(BigInt *Result, BigInt Number0, BigInt Number1);
void BigInt_Sub(BigInt *Result, BigInt Number0, BigInt Number1);
void BigInt_Resize(BigInt *BigInt);
void BigInt_Div(BigInt *Result, BigInt Number0, BigInt Number1);
void BigInt_Mod(BigInt *Result, BigInt Number0, BigInt Number1);
void BigInt_Sqrt(BigInt *Result, BigInt Number);
void BigInt_Pow(BigInt *Result, BigInt Base, BigInt Exponent);
void BigInt_Factorial(BigInt *Result, BigInt Number);
int BigInt_IsEqualTo(BigInt Number0, BigInt Number1);
int BigInt_IsNotEqualTo(BigInt Number0, BigInt Number1);
int BigInt_IsLessThan(BigInt Number0, BigInt Number1);
int BigInt_IsLessThanOrEqualTo(BigInt Number0, BigInt Number1);
int BigInt_IsGreaterThan(BigInt Number0, BigInt Number1);
int BigInt_IsGreaterThanOrEqualTo(BigInt Number0, BigInt Number1);
int BigInt_GetDecimalLength(BigInt Number);
void BigInt_GetAsString(BigInt Number, char *String);
void BigInt_Clean(BigInt *Number);
void BigInt_Debug(BigInt BigInt);
void BigInt_Abs(BigInt *BigInt);
void BigInt_GCD(BigInt *Result, BigInt Number0, BigInt Number1);
void BigInt_LCM(BigInt *Result, BigInt Number0, BigInt Number1);
void BigInt_SetFromString(BigInt *BigInt, char *Value);

/**
 * Multiples two BigInts together (Number0 and Number1), and stores the result into Result. The algorithm used depends on the operand sizes: for small sized arguments the standard multiplication method is used; for larger arguments, the Karatsuba algorithm is used.
 *
 * @param Result A pointer to a Bigint where the result should be stored.
 * @param Number0 First number.
 * @param Number1 Second number.
 * @return  
 */
void BigInt_Mul(BigInt *Result, BigInt Number0, BigInt Number1);

/**
 * Multiples two BigInts together (Number0 and Number1), and stores the result into Result, using the Karatsuba algorithm.
 *
 * @param Result A pointer to a Bigint where the result should be stored.
 * @param Number0 First number.
 * @param Number1 Second number.
 * @return  
 */
void BigInt_FastMul(BigInt *Result, BigInt Number0, BigInt Number1);

/**
 * Multiples two BigInts together (Number0 and Number1), and stores the result into Result, using the standard multiplication.
 *
 * @param Result A pointer to a Bigint where the result should be stored.
 * @param Number0 First number.
 * @param Number1 Second number.
 * @return  
 */
 void BigInt_SlowMul(BigInt *Result, BigInt Number0, BigInt Number1);

#endif